﻿unit Engine;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes,
  WorkThreadPool, MemoryPool, IOCompletionPort, Protocol, MemBuffer;

type
  //通道打开关闭事件
  TOnChannelDeviceEvent = procedure(FChannel: TObject) of object;
  //通道发送接收事件
  TOnChannelIOEvent = procedure(FChannel: TObject; FBuffer: TIBuffer; dwIoSize: Cardinal) of object;

  TIEngine = class
  private
    FEngineWorked: Boolean;
    FEngineShutDown: Boolean;
    FMemoryPool: TIMemoryPool;
    FEngineStarted: Boolean;
    FEngineName: string;
    FEngineType: TEngine_START_TYPE;
    FWorkThreadPool: TIWorkThreadPool;
    FIOCompletionPort: TIOCompletionPort;
    FOnChannelSendEvent: TOnChannelIOEvent;
    FOnChannelCloseEvent: TOnChannelDeviceEvent;
    FOnChannelRecvEvent: TOnChannelIOEvent;
    FOnChannelOpenEvent: TOnChannelDeviceEvent;
    //完成端口引擎启动
    procedure EngineRun;
    //完成端口异常处理
    procedure HandleExcept(const IOCPEventType: IO_POST_EVENT_TYPE; const Str: string);
    procedure m_OnChannelCloseEvent(const Value: TOnChannelDeviceEvent);
    procedure m_OnChannelOpenEvent(const Value: TOnChannelDeviceEvent);
    procedure m_OnChannelRecvEvent(const Value: TOnChannelIOEvent);
    procedure m_OnChannelSendEvent(const Value: TOnChannelIOEvent);
  protected
    // 完成端口消息处理
    procedure ProcessIOMessage(bRet: Boolean; dwCompletionKey: ULONG_PTR;
      pOverLappedEx: PTOverLappedEx; dwIOSize: Cardinal ); virtual;
  public
    constructor Create;
    destructor Destroy; override;
    //启动引擎
    function StartEngine: Boolean; virtual; abstract;
    //停止引擎
		procedure StopEngine; virtual; abstract;
  published
    property WorkThreadPool: TIWorkThreadPool read FWorkThreadPool;
    property MemoryPool: TIMemoryPool read FMemoryPool;
    property EngineName: String read FEngineName write FEngineName;
    property EngineType: TEngine_START_TYPE read FEngineType write FEngineType;
    property Started: Boolean read FEngineStarted write FEngineStarted;
    property ShutDown: Boolean read FEngineShutDown write FEngineShutDown;
    property EngineWorked: Boolean read FEngineWorked write FEngineWorked;
    property IOCompletionPort: TIOCompletionPort read FIOCompletionPort;
    property OnChannelOpenEvent: TOnChannelDeviceEvent read FOnChannelOpenEvent write m_OnChannelOpenEvent;
    property OnChannelCloseEvent: TOnChannelDeviceEvent read FOnChannelCloseEvent write m_OnChannelCloseEvent;
    property OnChannelRecvEvent: TOnChannelIOEvent read FOnChannelRecvEvent write m_OnChannelRecvEvent;
    property OnChannelSendEvent: TOnChannelIOEvent read FOnChannelSendEvent write m_OnChannelSendEvent;
  end;

implementation

uses ContextFactory;

{ TIEngine }

constructor TIEngine.Create;
begin
  inherited Create;
  FEngineStarted := False;
  FEngineShutDown := False;
  FEngineWorked := False;
  FIOCompletionPort := TIOCompletionPort.Create;
  FWorkThreadPool := TIWorkThreadPool.Create;
  FWorkThreadPool.OnCallBackEvent := EngineRun;
  FMemoryPool := TIMemoryPool.Create;
end;

destructor TIEngine.Destroy;
begin
  StopEngine;
  FreeAndNil(FWorkThreadPool);
  FreeAndNil(FMemoryPool);
  FreeAndNil(FIOCompletionPort);
  inherited Destroy;
end;

procedure TIEngine.EngineRun;
var
  xx: Integer;
  bIORet: LongBool;
  dwIOSize: Cardinal;
  dwCompletionKey: ULONG_PTR;
  pOverLappedEx: PTOverLappedEx;
  IOCPEventType: IO_POST_EVENT_TYPE;
begin
  IOCPEventType := IO_INITIALIZE;
  try
    while True do
    begin
      if not FEngineWorked then
      begin
        Sleep(100);
        Continue;
      end;
      pOverLappedEx := nil;
      IOCPEventType := IO_INITIALIZE;
      bIORet := FIOCompletionPort.GetQueuedCompletionStatus(dwIOSize,
        dwCompletionKey, POverlapped(pOverLappedEx));
      //根据pOverLappedEx得到操作类型
      if (Cardinal(pOverLappedEx) = IO_WORDTHREAD_EXIT) then
        begin
          //pOverLappedEx为空，判断是否投递关闭线程的操作
          if dwCompletionKey = 0 then
            Break
          else
            Continue;  //系统内部异常
        end
      else
        begin
          if (pOverLappedEx.FRequest = nil) then
            Continue
          else
           IOCPEventType := pOverLappedEx.FIOType;
        end;
      ProcessIOMessage(bIORet, Cardinal(dwCompletionKey), pOverLappedEx, dwIOSize);
    end;
  except
    on E: Exception do begin
      HandleExcept(IOCPEventType, E.Message);
    end;
  end;
end;

procedure TIEngine.HandleExcept(const IOCPEventType: IO_POST_EVENT_TYPE;
  const Str: string);
begin
  ;
end;

procedure TIEngine.m_OnChannelCloseEvent(const Value: TOnChannelDeviceEvent);
begin
  FOnChannelCloseEvent := Value;
end;

procedure TIEngine.m_OnChannelOpenEvent(const Value: TOnChannelDeviceEvent);
begin
  FOnChannelOpenEvent := Value;
end;

procedure TIEngine.m_OnChannelRecvEvent(const Value: TOnChannelIOEvent);
begin
  FOnChannelRecvEvent := Value;
end;

procedure TIEngine.m_OnChannelSendEvent(const Value: TOnChannelIOEvent);
begin
  FOnChannelSendEvent := Value;
end;

procedure TIEngine.ProcessIOMessage(bRet: Boolean; dwCompletionKey: ULONG_PTR;
  pOverLappedEx: PTOverLappedEx; dwIOSize: Cardinal);
begin
  ;
end;

end.
